#pragma once

typedef signed char s8;
typedef signed short s16;
typedef signed int s32;
typedef signed long long s64;
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;
typedef u32 size_t;
typedef u32 uintptr_t;

#define NULL ((void*)0)

#define CAT_(x, y) x ## y
#define CAT(x, y) CAT_(x, y)

#define OPAD(size) u8 CAT(_pad_, __COUNTER__)[size]
#define OSTRUCT(name, size) struct name { union { OPAD(size);
#define OSTRUCT_END };};
#define OFIELD(off, field) struct { OPAD(off); field; }

#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))

#define MIN(x,y) (((x) > (y)) ? (y) : (x))

#define DC_BASE 0x54200000
#define DSI_BASE 0x54300000
#define CLK_RST_BASE 0x60006000
#define MIPI_CAL_BASE 0x700E3000
#define SDHC_REG_BASE 0x700B0600

#define DC_CMD_STATE_ACCESS 0x54200100
#define DC_CMD_STATE_CONTROL 0x54200104
#define DC_DISP_BLEND_BACKGROUND_COLOR 0x54201390
#define DC_A_WIN_AD_WIN_OPTIONS 0x54202E00
#define DC_B_WIN_BD_WIN_OPTIONS 0x54203600
#define DC_C_WIN_CD_WIN_OPTIONS 0x54203E00

#define DSI_DSI_RD_DATA 0x54300024
#define DSI_DSI_WR_DATA 0x54300028
#define DSI_DSI_POWER_CONTROL 0x5430002C
#define DSI_HOST_DSI_CONTROL 0x5430003C
#define DSI_DSI_TRIGGER 0x5430004C
#define DSI_DSI_BTA_TIMING 0x543000FC
#define DSI_PAD_CONTROL 0x5430012C
#define DSI_DSI_VID_MODE_CONTROL 0x54300138

#define TIMERUS_CNTR_1US 0x60005010

#define GPIO_V_CNF 0x6000D504
#define GPIO_V_OE 0x6000D514
#define GPIO_V_OUT 0x6000D524

static inline u32 read32(uintptr_t addr) {
    return *(vu32 *)addr;
}

static inline void write32(uintptr_t addr, u32 val) {
    *(vu32 *)addr = val;
}

static inline void or32(uintptr_t addr, u32 val) {
    write32(addr, read32(addr) | val);
}

static inline void or32_masked(uintptr_t addr, u32 mask, u32 val) {
    write32(addr, (read32(addr) & ~mask) | val);
}
#define mask32 or32_masked

static inline void unset_bits(uintptr_t addr, u32 val) {
    write32(addr, read32(addr) & ~val);
}

static inline u32 get_ticks() {
    return read32(TIMERUS_CNTR_1US);
}

static inline void udelay(u32 usecs) {
    u32 start, now;
    start = now = get_ticks();
    while (now - start <= usecs) {
        now = get_ticks();
    }
}

void *memset(void *b, int c, size_t len);
void *memcpy(void *dst, const void *src, size_t len);
size_t strlen(const char *str);

#define INT_MAX ((int)0x7fffffff)
#define UINT_MAX ((unsigned int)0xffffffff)

#define LONG_MAX INT_MAX
#define ULONG_MAX UINT_MAX

#define LLONG_MAX ((long long)0x7fffffffffffffff)
#define ULLONG_MAX ((unsigned long long)0xffffffffffffffff)
